﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DPS.Prototype.Model;
using DPS.Prototype.PolicyBase.Manager;
using System.Threading;

namespace DPS.Prototype.PolicyBase
{
    public abstract class PolicyMakerBase
    {
        private  int _currentCycle = 0;

        private object receivingLockObj = new object();

        protected static Dictionary<int, Dictionary<string, Submission>> _innerSubmissions;

        private int competitorsCount;

        Dictionary<string, ProdCompetitorBase> competitors;

        public   int CurrentCycle
        {
            get { return this._currentCycle; }
        }

        public string CurrentBatchId
        {
            get;
            private set;
        }
        public PolicyMakerBase()
        {
            PolicyMakerBase._innerSubmissions = new Dictionary<int, Dictionary<string, Submission>>();
            this._currentCycle = 0;
            this.competitors = ProdCompetitorAllianceManager.Current.Alliance.GetAllProdCompetitors();
            this.competitorsCount = this.competitors.Count;
            this.CurrentBatchId = "Batch-" + DateTime.Now.ToString("yyyyMMddhhmmss");
        }


        public void Start()
        {
            if (this._currentCycle == 0)
            {
                TrackingManger.Current.Tracking.TrackingStartingBatch();
                StartNewCycle();
            }
            else
            {
                throw new InvalidOperationException("Can't start since of cuurent cycle no is not zero!");
            }
        }

        public void Stop()
        {
            TrackingManger.Current.Tracking.TrackingEndingBatch();
        }

        private void StartNewCycle()
        {

           
            this._currentCycle++;
            Dictionary<string, Submission> subMissions = new Dictionary<string, Submission>();
            PolicyMakerBase._innerSubmissions[this._currentCycle] = subMissions;
            PolicyOrder policyOrder = new PolicyOrder(OrderType.StartNewCycle);
            policyOrder["CycleNo"] = this.CurrentCycle;

            TrackingManger.Current.Tracking.TrackingStartingNewCycle();
            this.SendPolicyOrder(policyOrder);
        }

        public void ReceiveSubmission(Submission subMission)
        {
            if (subMission != null)
            {
                lock (receivingLockObj)
                {
                    PolicyMakerBase._innerSubmissions[this._currentCycle][subMission.ProdCompetitor.CompetitorName] = subMission;
                    
                    TrackingManger.Current.Tracking.TrackingReceivingNewSubMission(subMission);

                    if (PolicyMakerBase._innerSubmissions[this._currentCycle].Count == this.competitorsCount)
                    {
                        if (CheckEnd())
                        {
                            List<PolicyOrder> policyOrders = this.MakePolicy();
                            policyOrders.ForEach(policy => { this.SendPolicyOrder(policy); });

                            TrackingManger.Current.Tracking.TrackingStartingNewCycle();
                            TrackingManger.Current.Tracking.TrackingEndingNewCycle();

                            StartNewCycle();
                        }
                        else
                        {
                            Stop();
                        }
                    }
                }
            }
        }

        private bool CheckEnd() 
        {
            return PolicyMakerBase._innerSubmissions[this._currentCycle].Where(s => s.Value.Result != null).Count() > 0;
        }

        public void SendPolicyOrder(PolicyOrder policyOrder)
        {
            switch (policyOrder.OrderType)
            {
                case OrderType.StartNewCycle:
                    foreach (ProdCompetitorBase competitor in this.competitors.Values)
                    {
                        competitor.RecevieOrder(policyOrder);
                    }
                    break;
                case OrderType.ApproveThisCycle:
                    this.competitors[policyOrder.Submission.ProdCompetitor.CompetitorName].RecevieOrder(policyOrder);
                    break;
            }
        }

        #region Abstract Members
        protected abstract List<PolicyOrder> MakePolicy();
        #endregion

    }
}
